package l1j.server.server.clientpackets;

import static l1j.server.server.model.skill.L1SkillId.ABSOLUTE_BARRIER;
import static l1j.server.server.model.skill.L1SkillId.ADDITIONAL_FIRE;
import static l1j.server.server.model.skill.L1SkillId.AWAKEN_ANTHARAS;
import static l1j.server.server.model.skill.L1SkillId.AWAKEN_FAFURION;
import static l1j.server.server.model.skill.L1SkillId.AWAKEN_VALAKAS;
import static l1j.server.server.model.skill.L1SkillId.BOUNCE_ATTACK;
import static l1j.server.server.model.skill.L1SkillId.CALL_CLAN;
import static l1j.server.server.model.skill.L1SkillId.COUNTER_BARRIER;
import static l1j.server.server.model.skill.L1SkillId.DRAGON_SKIN;
import static l1j.server.server.model.skill.L1SkillId.FIRE_WALL;
import static l1j.server.server.model.skill.L1SkillId.ILLUSION_AVATAR;
import static l1j.server.server.model.skill.L1SkillId.ILLUSION_DIA_GOLEM;
import static l1j.server.server.model.skill.L1SkillId.ILLUSION_LICH;
import static l1j.server.server.model.skill.L1SkillId.ILLUSION_OGRE;
import static l1j.server.server.model.skill.L1SkillId.INSIGHT;
import static l1j.server.server.model.skill.L1SkillId.LIFE_STREAM;
import static l1j.server.server.model.skill.L1SkillId.MASS_TELEPORT;
import static l1j.server.server.model.skill.L1SkillId.MEDITATION;
import static l1j.server.server.model.skill.L1SkillId.MIRROR_IMAGE;
import static l1j.server.server.model.skill.L1SkillId.PANIC;
import static l1j.server.server.model.skill.L1SkillId.PATIENCE;
import static l1j.server.server.model.skill.L1SkillId.REDUCTION_ARMOR;
import static l1j.server.server.model.skill.L1SkillId.RUN_CLAN;
import static l1j.server.server.model.skill.L1SkillId.SOLID_CARRIAGE;
import static l1j.server.server.model.skill.L1SkillId.SOUL_OF_FLAME;
import static l1j.server.server.model.skill.L1SkillId.TELEPORT;
import static l1j.server.server.model.skill.L1SkillId.TRUE_TARGET;
import static l1j.server.server.model.skill.L1SkillId.BONE_BREAK;
import static l1j.server.server.model.skill.L1SkillId.CURSE_PARALYZE;
import static l1j.server.server.model.skill.L1SkillId.EARTH_BIND;
import static l1j.server.server.model.skill.L1SkillId.FOG_OF_SLEEPING;
import static l1j.server.server.model.skill.L1SkillId.FREEZING_BLIZZARD;
import static l1j.server.server.model.skill.L1SkillId.FREEZING_BREATH;
import static l1j.server.server.model.skill.L1SkillId.ICE_LANCE;
import static l1j.server.server.model.skill.L1SkillId.SHOCK_STUN;
import static l1j.server.server.model.skill.L1SkillId.SILENCE;
import static l1j.server.server.model.skill.L1SkillId.AREA_OF_SILENCE;
import static l1j.server.server.model.skill.L1SkillId.AI_TimeEffect;
import static l1j.server.server.model.skill.L1SkillId.NPC_FREEZING_BREATH;
import static l1j.server.server.model.skill.L1SkillId.TELEPORT_PROTECTION;
import l1j.opqlo.Server.L1World.L1World;
import l1j.server.echo.ClientThread;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.Instance.L1HummerInstance;
//import l1j.server.server.model.L1Object;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.skill.L1SkillId;
import l1j.server.server.model.skill.L1SkillUse;
import l1j.server.server.serverpackets.S_Paralysis;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.templates.L1Skills;

import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * 處理收到由客戶端傳來使用魔法的封包
 */
public class C_UseSkill extends ClientBasePacket {
	public static final int[] repeatedSkills ={CURSE_PARALYZE, SHOCK_STUN, EARTH_BIND, ICE_LANCE, FREEZING_BLIZZARD,
		FREEZING_BREATH, BONE_BREAK, FOG_OF_SLEEPING,SILENCE,AREA_OF_SILENCE,AI_TimeEffect,NPC_FREEZING_BREATH};
	private static final Logger _log = Logger.getLogger(C_UseSkill.class.getName());
	// 隱身狀態下可用的魔法
	/**去除 加速術43*/
	private static final int[] CAST_WITH_INVIS = { 1, 2, 3, 5, 8, 9, 12, 13,
		14, 19, 21, 26, 31, 32, 35, 37, 42, 44, 48, 49, 52, 54, 55, 57,
		60, 61, 63, 67, 68, 69, 72, 73, 75, 78, 79, REDUCTION_ARMOR,
		BOUNCE_ATTACK, SOLID_CARRIAGE, COUNTER_BARRIER, 97, 98, 99, 100,
		101, 102, 104, 105, 106, 107, 109, 110, 111, 113, 114, 115, 116,
		117, 118, 129, 130, 131, 133, 134, 137, 138, 146, 147, 148, 149,
		150, 151, 155, 156, 158, 159, 163, 164, 165, 166, 168, 169, 170,
		171, SOUL_OF_FLAME, ADDITIONAL_FIRE, DRAGON_SKIN, AWAKEN_ANTHARAS,
		AWAKEN_FAFURION, AWAKEN_VALAKAS, MIRROR_IMAGE, ILLUSION_OGRE,
		ILLUSION_LICH, PATIENCE, ILLUSION_DIA_GOLEM, INSIGHT, PANIC,
		ILLUSION_AVATAR};

	/**
	 * 該技能可否在隱身狀態使用
	 * @param useSkillid 技能編號
	 * @return true:可 false:不可
	 */
	private boolean isInvisUsableSkill(final int useSkillid) {
		for (final int skillId : CAST_WITH_INVIS) {
			if (skillId == useSkillid) {
				return true;
			}
		}
		return false;
	}

	@Override
	public void start(final byte[] decrypt, final ClientThread client) {
		try {
			// 資料載入
			this.read(decrypt);

			final L1PcInstance pc = client.getActiveChar();
			if (pc == null || pc.isTeleport() || pc.isDead()) {
				return;
			}
			if(pc.isInHell()){
				pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK, true));
				pc.sendPackets(new S_ServerMessage(563)); // \f1ここでは使えません。
				return;
			}
			if (!pc.getMap().isUsableSkill()|| pc.isPrivateShop()) {
				pc.sendPackets(new S_ServerMessage(563)); // \f1ここでは使えません。
				return;
			}
			if(pc._inFighting ==1 || pc._inFighting==3){
				pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK, true));
				return;
			}
			// スキルディレイ中使用不可
			if (pc.isSkillDelay()) {
				return;
			}
			//TODO 防止使用LHZ異常狀態正常喝水
			for (final int skills : repeatedSkills) {
				if(pc.hasSkillEffect(skills)){
					return;
				}
			}
			/*	// 檢查使用魔法的間隔
		if (Config.CHECK_SPELL_INTERVAL) {
			int result;
			// FIXME 判斷有向及無向的魔法
			if (SkillsTable.getInstance().getTemplate(skillId).getActionId() == ActionCodes.ACTION_SkillAttack) {
				result = pc.getAcceleratorChecker().checkInterval(AcceleratorChecker.ACT_TYPE.SPELL_DIR);
			}else {
				result = pc.getAcceleratorChecker().checkInterval(AcceleratorChecker.ACT_TYPE.SPELL_NODIR);
			}
			if (result == AcceleratorChecker.R_DISCONNECTED) {
				return;
			}
		}*/

			final int row = this.readC();
			final int column = this.readC();
			final int skillId = row * 8 + column + 1;

			if (skillId > 220) {
				return;
			}
			if (skillId < 0) {
				return;
			}
			if(pc._inFighting == 2){//競技場狀態
				if(skillId == L1SkillId.INVISIBILITY ||
						skillId == L1SkillId.BLIND_HIDING ||
						skillId == L1SkillId.ABSOLUTE_BARRIER){
					pc.sendPackets(new S_ServerMessage(1003));
					return;
				}
				// 隱身狀態可用魔法限制
			}if (pc.isInvisble() || pc.isInvisDelay()) {
				if (!this.isInvisUsableSkill(skillId)) {
					// 1003：透明狀態無法使用的魔法。
					pc.sendPackets(new S_ServerMessage(1003));
					return;
				}
			}

			if (!pc.isSkillMastery(skillId)) {
				return;
			}

			String charName = null;
			String message = null;
			int targetId = 0;
			int targetX = 0;
			int targetY = 0;
			if (decrypt.length > 4) {
				try {
					switch(skillId){
					case CALL_CLAN : case RUN_CLAN:
						charName = this.readS();
						if(charName == null){
							return;
						}
						break;
					case TRUE_TARGET:
						targetId = this.readD();
						targetX = this.readH();
						targetY = this.readH();
						message = this.readS();
						if(message == null){
							return;
						}
						break;
					case TELEPORT: case MASS_TELEPORT:
						this.readH(); // MapID
						targetId = this.readD(); // Bookmark ID
						break;
					case FIRE_WALL: case LIFE_STREAM:
						targetX = this.readH();
						targetY = this.readH();
						break;
					default:
						targetId = this.readD();
						targetX = this.readH();
						targetY = this.readH();
						break;

					}
				} catch (final Exception e) {
					_log.log(Level.SEVERE, "", e);
					return;
				}
			}

			/*	if(skillId == HASTE && targetId != pc.getId()){
				L1Object obj = L1World.getInstance().findObject(targetId);
				if(obj !=null){
					if(obj instanceof L1PcInstance){
						obj = null;
						return;
					}
				}
				obj = null;
			}*/

			if (pc.hasSkillEffect(ABSOLUTE_BARRIER)) { // アブソルート バリアの解除
				pc.killSkillEffectTimer(ABSOLUTE_BARRIER);
				pc.startHpRegeneration();
				pc.startMpRegeneration();
				pc.startMpRegenerationByDoll();
			}
			pc.killSkillEffectTimer(MEDITATION);
			if (skillId == CALL_CLAN || skillId == RUN_CLAN) { // コールクラン、ランクラン
				try {
					if (charName.isEmpty()) {
						// 名前が空の場合クライアントで弾かれるはず
						return;
					}
					final L1PcInstance target = L1World.getInstance().getPlayer(charName);
					if (target == null) {
						// メッセージが正確であるか未調査
						pc.sendPackets(new S_ServerMessage(73, charName)); // \f1%0はゲームをしていません。
						return;
					}
					if (pc.getClanid() != target.getClanid()) {
						pc.sendPackets(new S_ServerMessage(414)); // 同じ血盟員ではありません。
						return;
					}
					targetId = target.getId();
					if (skillId == CALL_CLAN) {
						// 移動せずに連続して同じクラン員にコールクランした場合、向きは前回の向きになる
						final int callClanId = pc.getCallClanId();
						if (callClanId == 0 || callClanId != targetId) {
							pc.setCallClanId(targetId);
							pc.setCallClanHeading(pc.getHeading());
						}
					}
				} catch (final Exception e) {
					_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
				}
			}
			final L1Object target = L1World.getInstance().findObject(targetId);
			if(target != null ){
				if(target instanceof L1PcInstance){
					if(((L1PcInstance) target).isTeleport()){
						return;
					}
					if(targetId != pc.getId() ){
						if(((L1PcInstance) target).hasSkillEffect(TELEPORT_PROTECTION)){
							pc.sendPackets(new S_SystemMessage("對方處於瞬移延遲中，無法對他施法。"));
							return;
						}else if(pc.hasSkillEffect(TELEPORT_PROTECTION)){
							pc.sendPackets(new S_SystemMessage("保護中無法PVP。"));
							return;
						}
					}
				}else if(target instanceof L1HummerInstance){
					return;
				}
			}
			final L1Skills temp = SkillsTable.getInstance().getTemplate(skillId);
			if(temp == null){
				return;
			}
			if(pc.getMapId() == 1784 && temp.getTarget().equals("attack")){
				pc.sendPackets(new S_ServerMessage(563)); // \f1ここでは使えません。
				return;
			}
			new L1SkillUse().handleCommands(pc, skillId, targetId, targetX, targetY,message, 0, L1SkillUse.TYPE_NORMAL);

		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		} finally {
			this.over();
		}
	}

}
